package com.zyb.ext.mybatis;

import com.zyb.ext.databasepool.IMyDatabaseConnPool;
import com.zyb.ext.databasepool.MyDatabaseConnPool;
import com.zyb.ext.databasepool.property.DBBean;
import com.zyb.ext.mybatis.annotate.ExtInsert;
import com.zyb.ext.mybatis.annotate.ExtParam;
import com.zyb.ext.mybatis.annotate.ExtSelect;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class MyInvocationHandler implements InvocationHandler {

    //计算某个字符出现的次数
    private AtomicInteger count;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        //模拟mybatis的插入操作
        ExtInsert extInsert = method.getDeclaredAnnotation(ExtInsert.class);
        if (extInsert != null) {
            return insertData(method, args, extInsert);
        }
        //模拟mybatis的查询操作
        ExtSelect extSelect = method.getDeclaredAnnotation(ExtSelect.class);
        if (extSelect != null) {
            return selectData(method, args, extSelect);
        }
        return null;
    }

    private Object selectData(Method method, Object[] args, ExtSelect extSelect) {
        //获取方法上注解中的sql语句
        String value = extSelect.value();
        //获取方法参数
        Parameter[] parameters = method.getParameters();
        //获取参数注解的值和参数值的对应关系
        Map<Object, Object> map = getParamAndValue(args, parameters);
        //获取sql中的参数名称
        List<String> paramList = subSelectSql(value);
        //将sql中的参数名称和参数的值对应起来
        List<Object> objects = new ArrayList<>();
        for (String param : paramList) {
            objects.add(map.get(param));
        }
        //把mapper中的sql编程jdbc可执行的sql
        String sql = getSQL(value);
        //执行SQL
        DBBean dbBean = new DBBean();
        IMyDatabaseConnPool myDatabaseConnPool = new MyDatabaseConnPool(dbBean);
        Connection connection = myDatabaseConnPool.getConnection();
        try {
            dbBean.select(connection, sql, objects);
            return null;
        } catch (SQLException e) {
            e.printStackTrace();
            log.info("执行sql异常：", e);
            return null;
        } finally {
            myDatabaseConnPool.destroyConnection(connection);
        }
    }

    private List<String> subSelectSql(String value) {
        count = new AtomicInteger();
        getCharCount(value);
        List<String> list = new ArrayList<>();
        for (int i = 0; i < count.get(); i++) {
            value = value.substring(value.indexOf("#{") + 2);
            String name = value.substring(0, value.indexOf("}"));
            list.add(name);
        }
        return list;
    }

    private Object insertData(Method method, Object[] args, ExtInsert extInsert) {
        //获取方法上注解的sql语句
        String value = extInsert.value();
        //获取方法参数
        Parameter[] parameters = method.getParameters();
        //获取参数注解的值和参数值的对应关系
        Map<Object, Object> map = getParamAndValue(args, parameters);
        //获取sql中的参数名称
        List<String> paramList = subInsertSql(value);
        //将sql中的参数名称和参数的值对应起来
        List<Object> objects = new ArrayList<>();
        System.out.println(paramList);
        for (String param : paramList) {
            objects.add(map.get(param));
        }
        //把mapper中的sql编程jdbc可执行的sql
        String sql = getSQL(value);
        //执行SQL
        DBBean dbBean = new DBBean();
        IMyDatabaseConnPool myDatabaseConnPool = new MyDatabaseConnPool(dbBean);
        Connection connection = myDatabaseConnPool.getConnection();
        try {
            return dbBean.insert(connection, sql, objects);
        } catch (SQLException e) {
            e.printStackTrace();
            log.info("执行sql异常：", e);
            return null;
        } finally {
            myDatabaseConnPool.destroyConnection(connection);
        }
    }

    private Map<Object, Object> getParamAndValue(Object[] args, Parameter[] parameters) {
        Map<Object, Object> map = new ConcurrentHashMap<>();
        if (parameters != null && parameters.length > 0) {
            for (int i = 0; i < parameters.length; i++) {
                //参数信息
                Parameter parameter = parameters[i];
                //参数注解
                ExtParam declaredAnnotation = parameter.getDeclaredAnnotation(ExtParam.class);
                if (declaredAnnotation != null) {
                    //参数的名称，注意这里使用的是ExtParam注解中的值
                    String paramNmae = declaredAnnotation.value();
                    //参数的值
                    Object arg = args[i];
                    map.put(paramNmae, arg);
                }
            }
        }
        return map;
    }

    //把mapper中的sql编程jdbc可执行的sql
    private String getSQL(String value) {
        count = new AtomicInteger();
        getCharCount(value);
        for (int i = 0; i < count.get(); i++) {
            int startChar = value.indexOf("#");
            int endChar = value.indexOf("}", startChar);
            value = value.replace(value.substring(startChar, endChar + 1), "?");
        }
        return value;
    }

    //计算字符出现的次数
    private void getCharCount(String value) {
        if (value.contains("#")) {
            //出现一次，叠加一次
            count.getAndIncrement();
            //把筛选过的字符过滤掉
            value = value.substring(value.indexOf("#") + 1);
            getCharCount(value);
        }
    }


    private List<String> subInsertSql(String value) {
        String values = value.substring(value.indexOf("values") + 6);
        String replace = values.replace("(#{", "").replace("},#{", ",").replace("})", "");
        return Arrays.asList(replace.split(","));
    }
}
